package com.ruoyi.web.controller.student.admin;


import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.domain.vo.ImportProgressVo;
import com.ruoyi.common.core.domain.vo.UploadFileVo;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.enums.OperatorType;
import com.ruoyi.common.utils.AESUtils;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.OrikaUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.utils.uuid.UUID;
import com.ruoyi.student.domain.StudentBaseInfo;
import com.ruoyi.student.domain.vo.*;
import com.ruoyi.student.service.IStudentBaseInfoService;
import com.ruoyi.student.service.IStudentService;
import com.ruoyi.student.service.ISysUserTeacherService;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysUserService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.RoundingMode;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;


/**
 * 管理员学生信息基础管理
 */
@RestController("AdminStudentBaseManageController")
@RequestMapping("/admin/student/baseinfo")
public class AdminStudentBaseManageController extends BaseController {
    /**
     * 学生基础信息表操作（单表操作）
     */
    @Resource
    private IStudentBaseInfoService studentBaseInfoService;

    /**
     * 学生操作（多表操作）
     */
    @Resource
    private IStudentService studentService;

    @Resource
    private ISysUserService sysUserService;

    @Resource
    private ISysUserTeacherService sysUserTeacherService;

    /**
     * 配置
     */
    @Resource
    private ISysConfigService configService;

    @Resource
    private RedisCache redisCache;


    /**
     * 获取学生列表
     *
     * @param vo
     * @return
     */
    @PreAuthorize("@ss.hasPermi('admin:student:baseinfo:list')")
    @Log(title = "管理员-查询学生列表", operatorType = OperatorType.MANAGE, businessType = BusinessType.QUERY)
    @GetMapping("/list")
    public TableDataInfo list(StudentListSearchVo vo) {
        startPage();
        List<StudentListVo> list = studentService.selectStudentList(vo);
        return getDataTable(list);
    }


    /**
     * 添加学生
     *
     * @param vo
     * @return
     */
    @PreAuthorize("@ss.hasPermi('admin:student:baseinfo:add')")
    @Log(title = "管理员-添加学生", operatorType = OperatorType.MANAGE, businessType = BusinessType.INSERT)
    @PostMapping()
    public AjaxResult add(@Valid @RequestBody StudentAddVo vo) throws Exception {
        LoginUser loginUser = getLoginUser();
        vo.setCreateBy(loginUser.getUsername());
        return success(studentService.addStudent(vo));
    }


    /**
     * 编辑学生
     *
     * @param vo
     * @return
     */
    @PreAuthorize("@ss.hasPermi('admin:student:baseinfo:edit')")
    @Log(title = "管理员-编辑学生", operatorType = OperatorType.MANAGE, businessType = BusinessType.UPDATE)
    @PutMapping()
    public AjaxResult edit(@Valid @RequestBody StudentEditVo vo) throws Exception {
        LoginUser loginUser = getLoginUser();
        vo.setUpdateBy(loginUser.getUsername());
        return success(studentService.editStudent(vo));
    }


    /**
     * 获取学生信息
     *
     * @param id
     * @return
     */
    @PreAuthorize("@ss.hasPermi('admin:student:baseinfo:info')")
    @Log(title = "管理员-查询单个学生信息", operatorType = OperatorType.MANAGE, businessType = BusinessType.QUERY)
    @GetMapping("/{id}")
    public AjaxResult getInfo(@PathVariable("id") Long id) throws Exception {
        StudentBaseInfo studentBaseInfo = studentBaseInfoService.selectStudentBaseInfoById(id);
        StudentInfoVo vo = new StudentInfoVo();
        BeanUtils.copyProperties(studentBaseInfo, vo);
        vo.setIdNumber(AESUtils.AESDeCode(vo.getIdNumber()));//解密身份证号
        return success(vo);
    }

    /**
     * 删除学生基础信息
     */
    @PreAuthorize("@ss.hasPermi('admin:student:baseinfo:remove')")
    @Log(title = "管理员-删除学生", operatorType = OperatorType.MANAGE, businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable Long[] ids) {
        return toAjax(studentService.deleteStudentByIds(ids));
    }

    /**
     * 根据关键字查询（同时查询名字和工号）教师列表
     * 注意：确认下这个方法辅导员是否有用到
     *
     * @param keyword
     * @return
     */
    @GetMapping("/search/teacher/{keyword}")
    public AjaxResult searchTeacherList(@PathVariable("keyword") String keyword) {
        return success(sysUserTeacherService.searchTeacherList(keyword));
    }


    /**
     * 导出学生基础信息列表
     */
    @PreAuthorize("@ss.hasPermi('admin:student:baseinfo:export')")
    @Log(title = "管理员-查询单个学生信息", operatorType = OperatorType.MANAGE, businessType = BusinessType.QUERY)
    @PostMapping("/export")
    public void export(HttpServletResponse response, StudentListSearchVo vo) {
        List<StudentExportListVo> list = studentService.selectStudentExportList(vo);
        list = list.stream().peek(x -> {
            try {
                x.setIdNumber(AESUtils.AESDeCode(x.getIdNumber()));
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }).collect(Collectors.toList());
        ExcelUtil<StudentExportListVo> util = new ExcelUtil<>(StudentExportListVo.class);
        util.exportExcel(response, list, "学生基础信息数据");
    }

    /**
     * 下载学生基础信息导入模板
     *
     * @param response
     * @throws Exception
     */
    @PostMapping("/downloadTemplate")
    public void downloadTemplate(HttpServletResponse response) throws Exception {
        String fileName = "student_base_info_template.xlsx";
        String path = configService.selectConfigByKey("sys.template.download.path");
        String filePath = path + fileName;
        File file = new File(filePath);
        if (file.exists()) {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8");
            FileUtils.setAttachmentResponseHeader(response, "student_base_info_template.xlsx");
            FileUtils.writeBytes(filePath, response.getOutputStream());
        }
    }


    /**
     * 上传学生信息文件
     *
     * @param file
     * @return
     * @throws Exception
     */
    @PreAuthorize("@ss.hasPermi('admin:student:baseinfo:uploadFile')")
    @Log(title = "管理员-上传学生数据文件", operatorType = OperatorType.MANAGE, businessType = BusinessType.IMPORT)
    @PostMapping("/upload")
    public AjaxResult uploadFile(MultipartFile file) throws IOException {
        String fileExt = FileUploadUtils.getExtension(file);//文件后缀名
        String newName = UUID.fastUUID().toString().replace("-", "");//随机生成uuid文件名
        String configPath = configService.selectConfigByKey("sys.upload.data.file.path");
        String savePath = configPath + newName + "." + fileExt;
        File newFile = new File(savePath);
        file.transferTo(newFile);
        return success(newName + "." + fileExt);
    }

    /**
     * 导入数据
     *
     * @param fileReq
     * @return
     * @throws Exception
     */
    @PreAuthorize("@ss.hasPermi('admin:student:baseinfo:importData')")
    @Log(title = "管理员-导入学生数据文件", operatorType = OperatorType.MANAGE, businessType = BusinessType.IMPORT)
    @PostMapping("/importData")
    public AjaxResult importData(@RequestBody UploadFileVo fileReq) throws Exception {
        LoginUser loginUser = getLoginUser();
        //Date now = DateUtils.getNowDate();//获取当前操作时间
        //获取上传路径
        String configPath = configService.selectConfigByKey("sys.upload.data.file.path");
        File file = new File(configPath + fileReq.getFileName());
        InputStream is = new FileInputStream(file);
        List<StudentBaseInfoTemplateVo> recordList = EasyExcel.read(is).head(StudentBaseInfoTemplateVo.class).sheet().doReadSync();
        List<StudentBaseInfoTemplateResultVo> resultList = new ArrayList<>();
        ImportProgressVo progressVo = new ImportProgressVo();
        if (recordList != null && recordList.size() > 0) {
            progressVo.setCountNum(recordList.size());//获取数据总数
            for (StudentBaseInfoTemplateVo vo : recordList) {
                //判断当前是否已经存在于系统
                Boolean result = studentBaseInfoService.checkExistByCode(vo.getCode());
                StudentBaseInfoTemplateResultVo resultVo = OrikaUtils.convert(vo, StudentBaseInfoTemplateResultVo.class);
                vo.setCreateBy(loginUser.getUsername());
                if (!result) {
                    //不存在，添加
                    try {
                        studentService.addStudent(vo);
                        resultVo.setOpStatus("添加成功");
                        resultList.add(resultVo);
                        progressVo.addSuccessNum();
                    } catch (Exception ex) {
                        //出错
                        resultVo.setOpStatus("添加失败");
                        resultVo.setMsg(ex.getMessage());
                        resultList.add(resultVo);
                        progressVo.addFailureNum();
                    }
                    progressVo.addOpNum();
                } else {
                    //存在，修改
                    try {
                        studentService.editStudentByImport(vo.getCode(), vo);
                        resultVo.setOpStatus("更新成功");
                        resultList.add(resultVo);
                        progressVo.addSuccessNum();
                    } catch (Exception ex) {
                        //出错
                        resultVo.setOpStatus("更新失败");
                        resultVo.setMsg(ex.getMessage());
                        resultList.add(resultVo);
                        progressVo.addFailureNum();
                    }
                }
                redisCache.setCacheObject(fileReq.getFileName(), this.getPercent(progressVo.getOpNum(), progressVo.getCountNum()));
            }
        }
        String fileExt = file.getName().substring(file.getName().lastIndexOf("."), file.getName().length());
        String newName = UUID.fastUUID().toString().replace("-", "");//随机生成uuid文件名
        String configResultPath = configService.selectConfigByKey("sys.upload.result.file.path");
        String resultFileName = configResultPath + newName + fileExt;
        EasyExcel.write(resultFileName, StudentBaseInfoTemplateResultVo.class).sheet("sheet1").registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).doWrite(resultList);
        progressVo.setResultFileName(newName + fileExt);
        redisCache.setCacheObject(fileReq.getFileName(), "100");
        //TODO 导入完成后，需要删除数据 或者 定时删除数据
        return success(progressVo);
    }


    /**
     * 获取当前文件的导入进度
     *
     * @param fileName
     * @return
     */
    @GetMapping("/importDataProgress/{fileName}")
    public AjaxResult importDataProgress(@PathVariable("fileName") String fileName) {
        if (StringUtils.isEmpty(fileName)) {
            return success(0);
        }
        String percent = redisCache.getCacheObject(fileName);
        if (StringUtils.isEmpty(percent)) {
            return success(0);
        }
        return success(percent);
    }


    /**
     * 导出上传结果
     *
     * @param response
     * @throws Exception
     * @RequestBody UploadFileVo fileReq,
     */
    //@PreAuthorize("@ss.hasPermi('admin:student:baseinfo:exportUploadResult')")
    @PostMapping("/exportUploadResult")
    public void exportUploadResult(@RequestParam(value = "fileName") String fileName, HttpServletResponse response) throws Exception {
        String path = configService.selectConfigByKey("sys.upload.result.file.path");
        String filePath = path + fileName;
        File file = new File(filePath);
        if (file.exists()) {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8");
            FileUtils.setAttachmentResponseHeader(response, fileName);
            FileUtils.writeBytes(filePath, response.getOutputStream());
        }
    }


    /**
     * 设定学生带兵
     *
     * @param vo
     * @return
     */
    @PreAuthorize("@ss.hasPermi('admin:student:baseinfo:setStudentLead')")
    @Log(title = "管理员-设置学生带兵", operatorType = OperatorType.MANAGE, businessType = BusinessType.UPDATE)
    @PutMapping("/setStudentLead")
    public AjaxResult setStudentLead(@Valid @RequestBody SetStudentLeadVo vo) {
        return success(studentService.setStudentLead(vo));
    }


    /**
     * 加密学生身份证号
     * 此方法只使用一次
     *
     * @return
     */
    @PreAuthorize("@ss.hasPermi('admin:student:baseinfo:encryptIdNumber')")
    @PutMapping("/encryptStudentIdNumber")
    public AjaxResult encryptStudentIdNumber() throws Exception {
        List<StudentBaseInfo> query = studentBaseInfoService.selectStudentBaseInfoList(null);
        for (StudentBaseInfo item : query) {
            LambdaUpdateWrapper<StudentBaseInfo> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
            lambdaUpdateWrapper.eq(StudentBaseInfo::getCode, item.getCode());
            lambdaUpdateWrapper.set(StudentBaseInfo::getIdNumber, AESUtils.AESEnCode(item.getIdNumber()));
            studentBaseInfoService.update(lambdaUpdateWrapper);
        }
        return success();
    }


    /**
     * 计算百分比
     * 不包含百分号
     * 非控制器
     *
     * @param x
     * @param y
     * @return
     */
    private String getPercent(Integer x, Integer y) {
        double f = x * 100 / y;
        NumberFormat nf = NumberFormat.getNumberInstance();
        nf.setRoundingMode(RoundingMode.HALF_UP);
        nf.setGroupingUsed(true);
        return nf.format(f);
    }


}
